﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using System.Data.Entity.Infrastructure;

using Seven.Tools;

namespace Seven.MsSql
{
    public static class QueryableExtensions
    {
        /// <summary>
        /// 指定要包括在查询结果中的相关对象。
        /// </summary>
        /// <typeparam name="TSource"><paramref name="_this"/> 中的元素的类型。</typeparam>
        /// <param name="_this">一个 <see cref="IQueryable&lt;TSource&gt;"/>，用于从中返回元素。</param>
        /// <param name="path">要在查询结果中返回的相关对象列表（表达式）。</param>
        /// <returns>一个新的 <see cref="IQueryable&lt;TSource&gt;"/>，它具有定义的查询路径。</returns>
        public static IQueryable<TSource> Include<TSource>(this IQueryable<TSource> _this, Expression<Func<TSource, object>> path)
            where TSource : class
        {
            string strPath = AnalyzeExpressionPath(path);
            Check.NotNull(strPath);

            //var query = queryable as ObjectQuery<TEntity>;//ObjectContext時用
            var query = _this as DbQuery<TSource>;//DbContext時用

            if (query != null) { return query.Include(strPath); }
            return null;
        }

        #region Private Methods

        /// <summary>
        /// 判定表达式中的S是否是TSource中的属性
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <typeparam name="S"></typeparam>
        /// <param name="expression"></param>
        /// <returns></returns>
        private static string AnalyzeExpressionPath<TSource, S>(Expression<Func<TSource, S>> expression)
            where TSource : class
        {
            if (expression == (Expression<Func<TSource, S>>)null)
            { throw new ArgumentNullException("Argument error"); }

            MemberExpression body = expression.Body as MemberExpression;
            if (((body == null) || !body.Member.DeclaringType.IsAssignableFrom(typeof(TSource))) || (body.Expression.NodeType != ExpressionType.Parameter))
            {
                throw new ArgumentException("Argument error");
            }
            else
            { return body.Member.Name; }
        }

        #endregion
    }
}
